﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;

using Storm.TextEditor.Parser.XML;

namespace Storm.TextEditor.Languages
{
	/// <summary>
	/// Represents a loader for all languages defined via Xml and in *.lang files.
	/// </summary>
	public sealed class LanguageLoader
	{
		#region Fields

		private static string dialogFilter             = "";
		private static string xmlLanguageFileExtension = ".lang";

		private static LanguageList languageList   = null;
		private static Hashtable    foundLanguages = new Hashtable();

		#endregion

		#region Properties

		/// <summary>
		/// Gets the dialog filter of all the languages combined.
		/// </summary>
		/// <value>The dialog filter.</value>
		public static string DialogFilter
		{
			get { return dialogFilter; }
			internal set { dialogFilter = value; }
		}

		/// <summary>
		/// Gets the file extension of a file that defines a language for the TextEditor to use.
		/// </summary>
		public static string XmlLanguageFileExtension
		{
			get { return xmlLanguageFileExtension; }
		}

		/// <summary>
		/// Gets the list of languages that a LanguageLoader can load.
		/// </summary>
		public static LanguageList LanguageList
		{
			get
			{
				if (languageList == null)
				{
					languageList = new LanguageList();
					XmlLanguage[] languages = (XmlLanguage[])Enum.GetValues(typeof(XmlLanguage));

					foreach (XmlLanguage currentLanguage in languages)
					{
						if (currentLanguage != XmlLanguage.None && currentLanguage != XmlLanguage.Unknown)
						{
							Stream fileStream = GetSyntaxStream(GetSyntaxFileName(currentLanguage));
							languageList.Add(Language.FromSyntaxFile(fileStream));
						}
					}
				}

				return languageList;
			}
		}

		/// <summary>
		/// Gets or sets the found languages.
		/// </summary>
		/// <value>The found languages.</value>
		public static Hashtable FoundLanguages
		{
			get { return foundLanguages; }
			internal set { foundLanguages = value; }
		}

		#endregion

		#region Methods

		#region Public

		/// <summary>
		/// Sets the language of a TextEditor to the specified XmlLanguage.
		/// </summary>
		/// <param name="editor">TextEditor to set language for.</param>
		/// <param name="language">New XmlLanguage for the specified TextEditor.</param>
		public static void SetSyntax(TextEditor editor, XmlLanguage language)
		{
			Stream fileStream = GetSyntaxStream(GetSyntaxFileName(language));
			editor.Document.Parser.Init(Language.FromSyntaxFile(fileStream));

			fileStream.Close();
		}

		/// <summary>
		/// Sets the language of a TextEditor to the specified file.
		/// </summary>
		/// <param name="editor">TextEditor to set language for.</param>
		/// <param name="filePath">New XmlLanguage defition file for the specified TextEditor.</param>
		public static void SetSyntax(TextEditor editor, string filePath)
		{
			editor.Document.Parser.Init(LanguageLoader.LanguageList.GetLanguageFromFile(filePath));
		}

		/// <summary>
		/// Returns a Language from the given XmlLanguage.
		/// </summary>
		/// <param name="language">XmlLanguage to generate a Language for.</param>
		public static Language GetLanguageFrom(XmlLanguage language)
		{
			Stream fileStream = GetSyntaxStream(GetSyntaxFileName(language));
			return Language.FromSyntaxFile(fileStream);
		}

		#endregion

		#region Private

		/// <summary>
		/// Returns a Stream for the specified path.
		/// </summary>
		/// <param name="filePath">Path to create a Stream for.</param>
		private static Stream GetSyntaxStream(string filePath)
		{
			Stream fileStream = typeof(LanguageLoader).Assembly.GetManifestResourceStream(filePath);
			return fileStream;
		}

		#endregion

		#region Internal

		/// <summary>
		/// Returns the path to the *.lang file defining the given XmlLanguage.
		/// </summary>
		/// <param name="language">XmlLanguage to find path for.</param>
		internal static string GetSyntaxFileName(XmlLanguage language)
		{
			if (language == XmlLanguage.None || language == XmlLanguage.Unknown)
				return "Storm.TextEditor.Languages.Text.lang";

			string filePath = Enum.GetName(typeof(XmlLanguage), language);
			filePath += xmlLanguageFileExtension;

			return "Storm.TextEditor.Languages." + filePath;
		}

		#endregion

		#endregion

		/// <summary>
		/// Initializes a new instance of LanguageLoader.
		/// </summary>
		public LanguageLoader()
		{
		}
	}
}
